package com.quectel.cms.controller.home;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.LambdaUtil;
import com.quectel.business.common.util.sys.SysCodeUtils;
import com.quectel.cms.controller.BaseController;
import com.quectel.cms.util.SessionHolder;
import com.quectel.cms.vo.home.CommonCountResp;
import com.quectel.cms.vo.home.CommonPieResp;
import com.quectel.cms.vo.home.TravelPersonTrendStatisticsVo;
import com.quectel.cms.vo.home.TravelStatisticsInfoVo;
import com.quectel.constant.core.ResourceGroupCodeConstants;
import com.quectel.constant.core.household.HouseholdCarConstants;
import com.quectel.constant.core.parking.ParkingOrderConstants;
import com.quectel.constant.core.parkingcard.ParkingCardOrderConstants;
import com.quectel.constant.global.SqlConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysCodeKeyConstants;
import com.quectel.core.module.car.dto.CarDto;
import com.quectel.core.module.car.dto.mongo.MongoCarAccessRecordDto;
import com.quectel.core.module.car.service.CarService;
import com.quectel.core.module.car.service.mongo.MongoCarAccessRecordService;
import com.quectel.core.module.carparking.dto.CarParkingSpaceDto;
import com.quectel.core.module.carparking.service.CarParkingSpaceService;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.core.module.entranceguard.dto.mongo.MongoPersonAccessRecordDto;
import com.quectel.core.module.entranceguard.service.mongo.MongoPersonAccessRecordService;
import com.quectel.core.module.household.dto.datav.PersonInOutTrendDto;
import com.quectel.core.module.parking.dto.CountOrderByTimeDto;
import com.quectel.core.module.parking.dto.ParkingOrderDto;
import com.quectel.core.module.parking.service.ParkingCurrentCarService;
import com.quectel.core.module.parking.service.ParkingOrderService;
import com.quectel.core.module.parkingcard.dto.CountCardOrderByTimeDto;
import com.quectel.core.module.parkingcard.dto.ParkingCardOrderDto;
import com.quectel.core.module.parkingcard.service.ParkingCardMemberService;
import com.quectel.core.module.parkingcard.service.ParkingCardOrderService;
import com.quectel.sys.module.sys.dto.SysCodeDto;
import com.quectel.util.common.DateUtils;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;

import static com.quectel.constant.global.StatisticsConstants.TIME_RANGE_BY_DAY;
import static com.quectel.constant.global.StatisticsConstants.TIME_RANGE_BY_MONTH;

/**
 * 在这里编写说明
 *
 * @author: bob
 * @email: bob.yu@quectel.com
 * @date: 2023-05-09 10:36:00
 */
@RestController
@RequestMapping("home/travel")
@Tag(name = "HomeTravelController", description = "安全出行首页相关api")
@Slf4j
public class HomeTravelController extends BaseController {

    public static final String START_TIME = "startTime", END_TIME = "endTime";

    @DubboReference
    private CarParkingSpaceService capParkingSpaceService;
    @DubboReference
    private CarService carService;
    @DubboReference
    private MongoCarAccessRecordService carRecordService;
    @DubboReference
    private MongoPersonAccessRecordService personAccessRecordService;
    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private ParkingCardOrderService parkingCardOrderService;
    @DubboReference
    private ParkingOrderService parkingOrderService;
    @DubboReference
    private ParkingCurrentCarService parkingCurrentCarService;
    @DubboReference
    private ParkingCardMemberService parkingCardMemberService;


    @GetMapping("parkCardOrderTrend")
    @Operation(summary = "停车月卡订单收费统计")
    public Response<CommonCountResp>parkCardOrderTrend(
            @Parameter(description = "日：DAY 月：MONTH") @RequestParam String type,
            @Parameter(description = "开始时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String startTime,
            @Parameter(description = "结束时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String endTime,
            @Parameter(description = "小区id") Long villageId
    ){
        Map<String, Object> params = new HashMap<>();

        SqlConstants.MysqlDateTimeFormatTypeEnum typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;
        Date startDate = null, endDate = null;
        String[] xData = null;
        switch (type) {
            case TIME_RANGE_BY_DAY:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.SIMPLE);
                endDate = DateUtil.endOfDay(DateUtils.parse(endTime, DateUtils.FormatType.SIMPLE));
                xData = DateUtils.timeSlotOfDay(startDate
                        , endDate, DateUtils.FormatType.SIMPLE, 1);
                break;
            case TIME_RANGE_BY_MONTH:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.MONTH;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.MONTH);
                endDate = DateUtil.endOfMonth(DateUtils.parse(endTime, DateUtils.FormatType.MONTH));
                xData = DateUtils.timeSlotOfMonth(startDate
                        , endDate, DateUtils.FormatType.MONTH, 1);
                break;
            default:
                xData = new String[]{};
        }

        Response<Object> checkResponse = checkTimeRange(type, DateUtils.format(startDate, DateUtils.FormatType.COMMON)
                , DateUtils.format(endDate, DateUtils.FormatType.COMMON), null);
        if (!checkResponse.isSuccess()) {
            return Response.error(checkResponse.getMessage());
        }

        params.put(LambdaUtil.getFieldName(ParkingCardOrderDto::getPayStatus), ParkingCardOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus());
        params.put(SqlConstants.DATE_FORMAT_TYPE_FILED, typeEnum.getFormat());
        params.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtils.format(startDate, DateUtils.FormatType.COMMON));
        params.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtils.format(endDate, DateUtils.FormatType.COMMON));
        fillAuthorityData(params);

        List<CountCardOrderByTimeDto> orderCountDtos = parkingCardOrderService.countOrderGroupByTime(params);
        Map<String, CountCardOrderByTimeDto> carAccessRecordCountDtoMap = new HashMap<>();
        for (CountCardOrderByTimeDto CountCardOrderByTimeDto : orderCountDtos) {
            carAccessRecordCountDtoMap.put(CountCardOrderByTimeDto.getDatetime(), CountCardOrderByTimeDto);
        }

        List<BigDecimal> amountList = new ArrayList<>();
        List<Integer> orderTotalList = new ArrayList<>();
        for (String xDatum : xData) {
            CountCardOrderByTimeDto countCardOrderByTimeDto = carAccessRecordCountDtoMap.get(xDatum);
            amountList.add(countCardOrderByTimeDto == null || countCardOrderByTimeDto.getPayAmount() == null ? BigDecimal.ZERO : countCardOrderByTimeDto.getPayAmount());
            orderTotalList.add(countCardOrderByTimeDto == null || countCardOrderByTimeDto.getOrderTotal() == null ? SystemConstants.ZERO.intValue() : countCardOrderByTimeDto.getOrderTotal());
        }

        CommonCountResp countResp = new CommonCountResp();
        countResp.setXData(xData);
        countResp.setYData(new CommonCountResp.DataInfo[]{
                new CommonCountResp.DataInfo("收费", amountList.toArray(new BigDecimal[0])),
                new CommonCountResp.DataInfo("订单数", orderTotalList.toArray(new Integer[0])),
        });
        return Response.<CommonCountResp>ok().wrap(countResp);
    }

    @GetMapping("parkOrderTrend")
    @Operation(summary = "停车订单收费统计")
    public Response<CommonCountResp>parkOrderTrend(
            @Parameter(description = "日：DAY 月：MONTH") @RequestParam String type,
            @Parameter(description = "开始时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String startTime,
            @Parameter(description = "结束时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String endTime,
            @Parameter(description = "小区id") Long villageId
    ){

        Map<String, Object> params = new HashMap<>();

        SqlConstants.MysqlDateTimeFormatTypeEnum typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;
        Date startDate = null, endDate = null;
        String[] xData = null;
        switch (type) {
            case TIME_RANGE_BY_DAY:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.SIMPLE);
                endDate = DateUtil.endOfDay(DateUtils.parse(endTime, DateUtils.FormatType.SIMPLE));
                xData = DateUtils.timeSlotOfDay(startDate
                        , endDate, DateUtils.FormatType.SIMPLE, 1);
                break;
            case TIME_RANGE_BY_MONTH:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.MONTH;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.MONTH);
                endDate = DateUtil.endOfMonth(DateUtils.parse(endTime, DateUtils.FormatType.MONTH));
                xData = DateUtils.timeSlotOfMonth(startDate
                        , endDate, DateUtils.FormatType.MONTH, 1);
                break;
            default:
                xData = new String[]{};
        }

        Response<Object> checkResponse = checkTimeRange(type, DateUtils.format(startDate, DateUtils.FormatType.COMMON)
                , DateUtils.format(endDate, DateUtils.FormatType.COMMON), null);
        if (!checkResponse.isSuccess()) {
            return Response.error(checkResponse.getMessage());
        }

        params.put(LambdaUtil.getFieldName(ParkingOrderDto::getPayStatus), ParkingOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus());
        params.put(SqlConstants.DATE_FORMAT_TYPE_FILED, typeEnum.getFormat());
        params.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtils.format(startDate, DateUtils.FormatType.COMMON));
        params.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), DateUtils.format(endDate, DateUtils.FormatType.COMMON));
        fillAuthorityData(params);

        List<CountOrderByTimeDto> orderCountDtos = parkingOrderService.countOrderGroupByTime(params);
        Map<String, CountOrderByTimeDto> carAccessRecordCountDtoMap = new HashMap<>();
        for (CountOrderByTimeDto countOrderByTimeDto : orderCountDtos) {
            carAccessRecordCountDtoMap.put(countOrderByTimeDto.getDatetime(), countOrderByTimeDto);
        }

        List<BigDecimal> amountList = new ArrayList<>();
        List<Integer> orderTotalList = new ArrayList<>();
        for (String xDatum : xData) {
            CountOrderByTimeDto countOrderByTimeDto = carAccessRecordCountDtoMap.get(xDatum);
            amountList.add(countOrderByTimeDto == null || countOrderByTimeDto.getPayAmount() == null ? BigDecimal.ZERO : countOrderByTimeDto.getPayAmount());
            orderTotalList.add(countOrderByTimeDto == null || countOrderByTimeDto.getOrderTotal() == null ? SystemConstants.ZERO.intValue() : countOrderByTimeDto.getOrderTotal());
        }

        CommonCountResp countResp = new CommonCountResp();
        countResp.setXData(xData);
        countResp.setYData(new CommonCountResp.DataInfo[]{
                new CommonCountResp.DataInfo("收费", amountList.toArray(new BigDecimal[0])),
                new CommonCountResp.DataInfo("订单数", orderTotalList.toArray(new Integer[0])),
        });
        return Response.<CommonCountResp>ok().wrap(countResp);
    }

    @GetMapping("carInOutTrend")
    @Operation(summary = "车辆进出趋势折线图")
    public Response<CommonCountResp> carInOutTrend(
            @Parameter(description = "日：DAY 月：MONTH") @RequestParam String type,
            @Parameter(description = "开始时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String startTime,
            @Parameter(description = "结束时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String endTime,
            @Parameter(description = "小区id") Long villageId) {

        Map<String, Object> params = new HashMap<>();

        SqlConstants.MysqlDateTimeFormatTypeEnum typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;
        Date startDate = null, endDate = null;
        String[] xData = null;
        switch (type) {
            case TIME_RANGE_BY_DAY:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.SIMPLE);
                endDate = DateUtils.parse(endTime, DateUtils.FormatType.SIMPLE);
                xData = DateUtils.timeSlotOfDay(startDate
                        , endDate, DateUtils.FormatType.SIMPLE, 1);
                params.put("startTime", DateUtil.format(startDate, "yyyy-MM-dd") + " 00:00:00");
                params.put("endTime", DateUtil.format(endDate, "yyyy-MM-dd") + " 23:59:59");

                break;
            case TIME_RANGE_BY_MONTH:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.MONTH;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.MONTH);
                endDate = DateUtils.parse(endTime, DateUtils.FormatType.MONTH);
                xData = DateUtils.timeSlotOfMonth(startDate
                        , endDate, DateUtils.FormatType.MONTH, 1);

                break;
            default:
                xData = new String[]{};
        }

        params.put(SqlConstants.DATE_FORMAT_TYPE_FILED, typeEnum.getFormat());
        params.put(LambdaUtil.getFieldName(MongoCarAccessRecordDto::getTenantId), SessionHolder.getSysUser().getTenantId());
        params.put(LambdaUtil.getFieldName(MongoCarAccessRecordDto::getVillageId), villageId);
        // 进
        params.put(LambdaUtil.getFieldName(MongoCarAccessRecordDto::getOutOrIn), HouseholdCarConstants.IN);
        List<PersonInOutTrendDto> inResultList = carRecordService.groupTimeType(params);
        // 出
        params.put(LambdaUtil.getFieldName(MongoCarAccessRecordDto::getOutOrIn), HouseholdCarConstants.IN);
        List<PersonInOutTrendDto> outResultList = carRecordService.groupTimeType(params);

        List<TravelPersonTrendStatisticsVo> outInResult = new ArrayList<>();
        for (PersonInOutTrendDto statisticsVo : inResultList) {
            TravelPersonTrendStatisticsVo personTrendStatisticsVo = new TravelPersonTrendStatisticsVo();
            personTrendStatisticsVo.setDateTime(statisticsVo.getTime());
            personTrendStatisticsVo.setInNum(statisticsVo.getCount());
            outInResult.add(personTrendStatisticsVo);
        }

        for (TravelPersonTrendStatisticsVo inOutTrendDto : outInResult) {
            for (PersonInOutTrendDto outTrendDto : outResultList) {
                if (inOutTrendDto.getDateTime().equals(outTrendDto.getTime())) {
                    inOutTrendDto.setOutNum(outTrendDto.getCount());
                }
            }
        }

        Map<String, TravelPersonTrendStatisticsVo> personTrendStatisticsVoMap = new HashMap<>();
        for (TravelPersonTrendStatisticsVo statisticsVo : outInResult) {
            personTrendStatisticsVoMap.put(statisticsVo.getDateTime(), statisticsVo);
        }


        List<Integer> inNums = new ArrayList<>();
        List<Integer> outNums = new ArrayList<>();
        for (String key : xData) {
            TravelPersonTrendStatisticsVo personTrendStatisticsVo = personTrendStatisticsVoMap.get(key);
            inNums.add(personTrendStatisticsVo == null ? 0 : personTrendStatisticsVo.getInNum());
            outNums.add(personTrendStatisticsVo == null ? 0 : personTrendStatisticsVo.getOutNum());
        }

        CommonCountResp countResp = new CommonCountResp();
        countResp.setXData(xData);
        countResp.setYData(new CommonCountResp.DataInfo[]{
                new CommonCountResp.DataInfo("进入", inNums.stream().toArray(Integer[]::new)),
                new CommonCountResp.DataInfo("离开", outNums.stream().toArray(Integer[]::new))
        });
        return Response.<CommonCountResp>ok().wrap(countResp);
    }

    @GetMapping("personInOutTrend")
    @Operation(summary = "人员进出趋势折线图")
    public Response<CommonCountResp> personInOutTrend(
            @Parameter(description = "日：DAY 月：MONTH") @RequestParam String type,
            @Parameter(description = "开始时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String startTime,
            @Parameter(description = "结束时间 日:传入yyyy-MM-dd  月：传入yyyy-MM") @RequestParam String endTime,
            @Parameter(description = "小区id") Long villageId) {

        Long tenantId = SessionHolder.getSysUser().getTenantId();

        Map<String, Object> params = new HashMap<>();

        SqlConstants.MysqlDateTimeFormatTypeEnum typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;
        Date startDate = null, endDate = null;
        String[] xData = null;
        switch (type) {
            case TIME_RANGE_BY_DAY:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.DAY;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.SIMPLE);
                endDate = DateUtils.parse(endTime, DateUtils.FormatType.SIMPLE);
                xData = DateUtils.timeSlotOfDay(startDate
                        , endDate, DateUtils.FormatType.SIMPLE, 1);
                params.put("startTime", DateUtil.format(startDate, "yyyy-MM-dd") + " 00:00:00");
                params.put("endTime", DateUtil.format(endDate, "yyyy-MM-dd") + " 23:59:59");

                break;
            case TIME_RANGE_BY_MONTH:
                typeEnum = SqlConstants.MysqlDateTimeFormatTypeEnum.MONTH;

                startDate = DateUtils.parse(startTime, DateUtils.FormatType.MONTH);
                endDate = DateUtils.parse(endTime, DateUtils.FormatType.MONTH);
                xData = DateUtils.timeSlotOfMonth(startDate
                        , endDate, DateUtils.FormatType.MONTH, 1);

                break;
            default:
                xData = new String[]{};
        }

        params.put(SqlConstants.DATE_FORMAT_TYPE_FILED, typeEnum.getFormat());
        params.put(LambdaUtil.getFieldName(MongoPersonAccessRecordDto::getTenantId),tenantId );
        params.put(LambdaUtil.getFieldName(MongoPersonAccessRecordDto::getVillageId), villageId);
        // 进
        params.put(LambdaUtil.getFieldName(MongoPersonAccessRecordDto::getOutOrIn), HouseholdCarConstants.IN);
        List<PersonInOutTrendDto> inResultList = personAccessRecordService.groupTimeType(params);
        // 出
        params.put(LambdaUtil.getFieldName(MongoPersonAccessRecordDto::getOutOrIn), HouseholdCarConstants.OUT);
        List<PersonInOutTrendDto> outResultList = personAccessRecordService.groupTimeType(params);

        List<TravelPersonTrendStatisticsVo> outInResult = new ArrayList<>();
        for (PersonInOutTrendDto statisticsVo : inResultList) {
            TravelPersonTrendStatisticsVo personTrendStatisticsVo = new TravelPersonTrendStatisticsVo();
            personTrendStatisticsVo.setDateTime(statisticsVo.getTime());
            personTrendStatisticsVo.setInNum(statisticsVo.getCount());
            outInResult.add(personTrendStatisticsVo);
        }

        for (TravelPersonTrendStatisticsVo inOutTrendDto : outInResult) {
            for (PersonInOutTrendDto outTrendDto : outResultList) {
                if (inOutTrendDto.getDateTime().equals(outTrendDto.getTime())){
                    inOutTrendDto.setOutNum(outTrendDto.getCount());
                }
            }
        }

        Map<String, TravelPersonTrendStatisticsVo> personTrendStatisticsVoMap = new HashMap<>();
        for (TravelPersonTrendStatisticsVo statisticsVo : outInResult) {
            personTrendStatisticsVoMap.put(statisticsVo.getDateTime(), statisticsVo);
        }


        List<Integer> inNums = new ArrayList<>();
        List<Integer> outNums = new ArrayList<>();
        for (String key : xData) {
            TravelPersonTrendStatisticsVo personTrendStatisticsVo = personTrendStatisticsVoMap.get(key);
            inNums.add(personTrendStatisticsVo == null ? 0 : personTrendStatisticsVo.getInNum());
            outNums.add(personTrendStatisticsVo == null ? 0 : personTrendStatisticsVo.getOutNum());
        }

        CommonCountResp countResp = new CommonCountResp();
        countResp.setXData(xData);
        countResp.setYData(new CommonCountResp.DataInfo[]{
                new CommonCountResp.DataInfo("进入", inNums.stream().toArray(Integer[]::new)),
                new CommonCountResp.DataInfo("离开", outNums.stream().toArray(Integer[]::new))
        });
        return Response.<CommonCountResp>ok().wrap(countResp);
    }

    /**
     * 安全出行-首页多维度数量统计
     * @param villageId
     * @return
     */
    @GetMapping("statisticsInfo")
    @Operation(summary = "安全出行首页-多维度数量统计")
    public Response<TravelStatisticsInfoVo> propertyStatisticsInfo(
            @Parameter(description = "小区id") @RequestParam Long villageId) {

        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());
        request.put(LambdaUtil.getFieldName(DeviceDto::getVillageId), villageId);
        request.put(START_TIME, DateUtil.format(DateUtil.beginOfDay(new Date()), DatePattern.NORM_DATETIME_PATTERN));
        request.put(END_TIME,DateUtil.format(DateUtil.endOfDay(new Date()), DatePattern.NORM_DATETIME_PATTERN));

        int todayHouseholdInOutCount = personAccessRecordService.countTotal(request.getParams());

        int todayCarInOutCount = carRecordService.countTotal(request.getParams());


        super.fillResourceGroupCode(request.getParams(), ResourceGroupCodeConstants.CAR_GATE_GROUP);
        int parkingGateCount = deviceService.queryTotal(request.getParams());

        super.fillResourceGroupCode(request.getParams(), ResourceGroupCodeConstants.ENTRANCE_GUARD_GROUP);
        int entranceGuardCount = deviceService.queryTotal(request.getParams());

        int parkingCarCount = parkingCurrentCarService.queryTotal(request.getParams());

        TravelStatisticsInfoVo vo = new TravelStatisticsInfoVo();
        vo.setTodayHouseholdInOutCount(todayHouseholdInOutCount);
        vo.setTodayCarInOutCount(todayCarInOutCount);
        vo.setParkingGateCount(parkingGateCount);
        vo.setEntranceGuardCount(entranceGuardCount);
        vo.setParkingCarCount(parkingCarCount);


        return Response.<TravelStatisticsInfoVo>ok().wrap(vo);
    }

    /**
     * 月卡环形统计
     */
    @GetMapping("validCardStatistics")
    @Operation(summary = "月卡环形统计")
    public Response<CommonPieResp> validCardStatistics(
            @Parameter(description = "开始时间 yyyy-MM-dd") @RequestParam String startTime,
            @Parameter(description = "结束时间 yyyy-MM-dd") @RequestParam String endTime,
            @Parameter(description = "小区id") Long villageId
    ) {
        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());

        String startTimeStr = DateUtils.format(DateUtil.beginOfDay(DateUtils.parse(startTime, DateUtils.FormatType.SIMPLE)), DateUtils.FormatType.COMMON);
        String endTimeStr = DateUtils.format(DateUtil.endOfDay(DateUtils.parse(endTime, DateUtils.FormatType.SIMPLE)), DateUtils.FormatType.COMMON);

        Response<Object> checkResponse = checkTimeRange(TIME_RANGE_BY_MONTH, startTimeStr, endTimeStr, null);
        if (!checkResponse.isSuccess()) {
            return Response.error(checkResponse.getMessage());
        }

        request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getLeft(), startTimeStr);
        request.put(SystemConstants.TIME_SLOT_KEY_PAIR.getRight(), endTimeStr);

        request.put(LambdaUtil.getFieldName(ParkingCardOrderDto::getPayStatus), ParkingCardOrderConstants.OrderPayStatusEnum.PAY_SUCCESS.getPayStatus());

        int queryTotal = parkingCardOrderService.queryTotal(request.getParams());
        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark(SysCodeKeyConstants.PARKING_CARD_TYPE);

        List<CommonPieResp.PieInfo> eventList = new ArrayList<>();

        if (queryTotal > 0) {
            for (SysCodeDto sysCodeDto : categoryCodeList) {
                CommonPieResp.PieInfo pieInfo = new CommonPieResp.PieInfo();
                pieInfo.setName(sysCodeDto.getName());
                request.put(LambdaUtil.getFieldName(ParkingCardOrderDto::getCardType), sysCodeDto.getValue());
                int count = parkingCardOrderService.queryTotal(request.getParams());
                pieInfo.setValue((double) count);
                eventList.add(pieInfo);
            }
        }

        CommonPieResp commonCountResp = new CommonPieResp();
        commonCountResp.setTotal((double) queryTotal);
        commonCountResp.setPieData(eventList.toArray(new CommonPieResp.PieInfo[0]));
        return Response.<CommonPieResp>ok().wrap(commonCountResp);
    }

    /**
     * 车位环形统计
     */
    @GetMapping("carSpaceStatistics")
    @Operation(summary = "车位环形统计")
    public Response<CommonPieResp> carSpaceStatistics(@Parameter(description = "小区id") Long villageId) {
        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());


        int queryTotal = capParkingSpaceService.queryTotal(request.getParams());
        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark(SysCodeKeyConstants.CAR_PARKING_SPACE_TYPE);

        List<CommonPieResp.PieInfo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            CommonPieResp.PieInfo pieInfo = new CommonPieResp.PieInfo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(CarParkingSpaceDto::getType), sysCodeDto.getValue());
            int count = capParkingSpaceService.queryTotal(request.getParams());
            pieInfo.setValue(Double.valueOf(count));
            eventList.add(pieInfo);
        }

        CommonPieResp commonCountResp = new CommonPieResp();
        commonCountResp.setTotal(Double.valueOf(queryTotal));
        commonCountResp.setPieData(eventList.toArray(new CommonPieResp.PieInfo[0]));
        return Response.<CommonPieResp>ok().wrap(commonCountResp);
    }

    /**
     * 车辆环形统计
     */
    @GetMapping("carStatistics")
    @Operation(summary = "车辆统计")
    public Response<CommonPieResp> carStatistics(@Parameter(description = "小区id") Long villageId) {
        Request request = Request.configParams(Request.parseParams(httpServletRequest));
        super.fillAuthorityData(request.getParams());


        int queryTotal = carService.queryTotal(request.getParams());
        List<SysCodeDto> categoryCodeList = SysCodeUtils.easyToGetByMark(SysCodeKeyConstants.CAR_TYPE);

        List<CommonPieResp.PieInfo> eventList = new ArrayList<>();
        for (SysCodeDto sysCodeDto : categoryCodeList) {
            CommonPieResp.PieInfo pieInfo = new CommonPieResp.PieInfo();
            pieInfo.setName(sysCodeDto.getName());
            request.put(LambdaUtil.getFieldName(CarDto::getCarType), sysCodeDto.getValue());
            int count = carService.queryTotal(request.getParams());
            pieInfo.setValue(Double.valueOf(count));
            eventList.add(pieInfo);
        }

        CommonPieResp commonCountResp = new CommonPieResp();
        commonCountResp.setTotal(Double.valueOf(queryTotal));
        commonCountResp.setPieData(eventList.toArray(new CommonPieResp.PieInfo[0]));
        return Response.<CommonPieResp>ok().wrap(commonCountResp);
    }

}
